Amazon OpenSearch ServerlessにAWS Lambdaからアクセスできなくて困った話
ゲームソリューション部の えがわ です。
LambdaからOpenSearch Serverlessへのアクセスに少し詰まってしまったので、備忘録として残しておきます。
最初に結論
以下の設定を行っていませんでした。
- Lambdaの実行ロールにOpenSearch Serverlessの権限を追加
- OpenSearch ServerlessのデータアクセスコントロールにLambdaの実行ロールを指定
事前準備
OpenSearch Serverlessのコレクションは作成済みとします。
今回はベクトル検索で試しています。
やったこと
OpenSearch Serverlessのインデックスを作成する処理を実行してみます。
エンドポイントやリージョン、インデックス名は適宜修正してください。
from opensearchpy import OpenSearch, RequestsHttpConnection, AWSV4SignerAuth import boto3 def lambda_handler(event, context): host = 'endpoint' #without https:// region = 'us-east-1' service = 'aoss' credentials = boto3.Session().get_credentials() auth = AWSV4SignerAuth(credentials, region, service) client = OpenSearch( hosts=[{'host': host, 'port': 443}], http_auth=auth, use_ssl=True, verify_certs=True, connection_class=RequestsHttpConnection ) index_name = 'index-name' client.indices.create(index_name, body={ "settings":{ "index.knn": True }, "mappings":{ "properties": { "values": { "type": "knn_vector", "dimension": 1024 }, "title": { "type": "text" } } } } )
AWS SDK for Pandas
のレイヤー追加しておくとopensearch-py
も使用できます。
Lambdaをそのまま実行してみると以下のエラーが発生します。
{ "errorMessage": "AuthorizationException(403, 'Forbidden')", "errorType": "AuthorizationException", "requestId": "fe4c4987-3ab5-4264-b317-b06249d1c11b", "stackTrace": [ " File \"/var/task/lambda_function.py\", line 22, in lambda_handler\n client.indices.create(index_name,\n", " File \"/opt/python/opensearchpy/client/utils.py\", line 180, in _wrapped\n return func(*args, params=params, headers=headers, **kwargs)\n", " File \"/opt/python/opensearchpy/client/indices.py\", line 164, in create\n return self.transport.perform_request(\n", " File \"/opt/python/opensearchpy/transport.py\", line 447, in perform_request\n raise e\n", " File \"/opt/python/opensearchpy/transport.py\", line 408, in perform_request\n status, headers_response, data = connection.perform_request(\n", " File \"/opt/python/opensearchpy/connection/http_requests.py\", line 231, in perform_request\n self._raise_error(\n", " File \"/opt/python/opensearchpy/connection/base.py\", line 315, in _raise_error\n raise HTTP_EXCEPTIONS.get(status_code, TransportError)(\n" ] }
ははーん、このエラーはLambdaの実行ロールのポリシーですね!?
ということで、実行ロールにポリシーを追加します。
↓のポリシー追加は後に分かりますが間違った手順です。
実行ロールを選択し
OpenSearchServiceのポリシーを追加します。
とりあえず困ったときのFullAccessを追加しています。
再度Lambdaを実行します。
{ "errorMessage": "AuthorizationException(403, 'Forbidden')", "errorType": "AuthorizationException", "requestId": "a3bb8f14-5e71-49d1-9f67-f9e341a97393", "stackTrace": [ " File \"/var/task/lambda_function.py\", line 22, in lambda_handler\n client.indices.create(index_name,\n", " File \"/opt/python/opensearchpy/client/utils.py\", line 180, in _wrapped\n return func(*args, params=params, headers=headers, **kwargs)\n", " File \"/opt/python/opensearchpy/client/indices.py\", line 164, in create\n return self.transport.perform_request(\n", " File \"/opt/python/opensearchpy/transport.py\", line 447, in perform_request\n raise e\n", " File \"/opt/python/opensearchpy/transport.py\", line 408, in perform_request\n status, headers_response, data = connection.perform_request(\n", " File \"/opt/python/opensearchpy/connection/http_requests.py\", line 231, in perform_request\n self._raise_error(\n", " File \"/opt/python/opensearchpy/connection/base.py\", line 315, in _raise_error\n raise HTTP_EXCEPTIONS.get(status_code, TransportError)(\n" ] }
なにも変わらない...
先ほど追加したポリシーを確認すると"es"
のFullAccessを付与していますが、今回はServerlessなので"aoss"
の付与を行う必要がありそうです。
AWSは提供してなさそうにみえるので、インラインポリシーを作成
からポリシーを作成していきます。
OpenSearch Serverlessのポリシーを検索し、またまた困ったときのFullAccessを追加してみます。
再度Lambdaを実行します。
{ "errorMessage": "AuthorizationException(403, 'security_exception', 'OpenSearch exception [type=authorization_exception, reason=User does not have permissions for the requested resource]')", "errorType": "AuthorizationException", "requestId": "be8f0954-a261-4b0b-acbd-704863c54860", "stackTrace": [ " File \"/var/task/lambda_function.py\", line 22, in lambda_handler\n client.indices.create(index_name,\n", " File \"/opt/python/opensearchpy/client/utils.py\", line 180, in _wrapped\n return func(*args, params=params, headers=headers, **kwargs)\n", " File \"/opt/python/opensearchpy/client/indices.py\", line 164, in create\n return self.transport.perform_request(\n", " File \"/opt/python/opensearchpy/transport.py\", line 447, in perform_request\n raise e\n", " File \"/opt/python/opensearchpy/transport.py\", line 408, in perform_request\n status, headers_response, data = connection.perform_request(\n", " File \"/opt/python/opensearchpy/connection/http_requests.py\", line 231, in perform_request\n self._raise_error(\n", " File \"/opt/python/opensearchpy/connection/base.py\", line 315, in _raise_error\n raise HTTP_EXCEPTIONS.get(status_code, TransportError)(\n" ] }
403は継続して発生していますが、エラーは変わりました!
OpenSearch Serverlessへ近づいているように見えます!
コレクションの権限周りに問題がありそうなので、マネジメントコンソールを眺めてみます。
セキュリティのデータアクセスポリシーが怪しそうな気がするので、ポリシーを確認してみます。
選択されたプリンシパル
にコレクションを作成したロールが設定されています。
ここにLambdaの実行ロールを設定すればうまく動きそうな予感がしています。
再度Lambdaを実行します。
成功しました!
インデックスも追加されています。
最後に
今回、AWS LambdaからAmazon OpenSearch Serverlessへアクセスする際の困った内容について記載しました。
この記事がどなたかの参考になれば幸いです。